package com.ltmonitor.jt808.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;

import javax.annotation.Resource;

import com.ltmonitor.jt808.protocol.*;
import com.ltmonitor.service.*;
import com.ltmonitor.util.DateUtil;
import com.ltmonitor.vo.AGpsResult;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.ltmonitor.entity.GPSRealData;
import com.ltmonitor.entity.Terminal;
import com.ltmonitor.entity.TerminalCommand;
import com.ltmonitor.entity.VehicleData;
import com.ltmonitor.jt808.service.IAckService;
import com.ltmonitor.jt808.service.ICommandParseService;
import com.ltmonitor.jt808.service.IMessageSender;
import com.ltmonitor.jt808.service.ITransferGpsService;
import com.ltmonitor.jt809.entity.VehicleRegisterInfo;

/**
 * 终端应答服务
 * 1.对终端上传的数据按照808协议文档要求进行应答
 * 2.将终端注册信息转发给809服务器
 * @author admin
 *
 */
@Service("ackService")
public class AckService implements IAckService {

	private static Logger logger = Logger.getLogger(AckService.class);
	// private ConcurrentLinkedQueue<T808Message> dataQueue = new
	// ConcurrentLinkedQueue();

	@Autowired
	private ICommandParseService commandParseService;

	private IMessageSender messageSender;

	@Resource
	private IRealDataService realDataService;

	@Autowired
	private IVehicleDataService vehicleDataService;
	@Autowired
	private ITerminalService terminalService;

	/**
	 * 鉴权码
	 */
	@Value("#{config.authencateNo}")  
	private String authencateNo = "1234567890A"; 

	private ConcurrentHashMap<String, String> vehicleRegisterMap = new ConcurrentHashMap<String, String>();
	private ConcurrentHashMap<String, String> terminalRegisterMap = new ConcurrentHashMap<String, String>();
	private ConcurrentHashMap<String, String> registerMap = new ConcurrentHashMap<String, String>();

	private ConcurrentHashMap<String, VehicleRegisterInfo> vehicleRegisterInfoMap = new ConcurrentHashMap<String, VehicleRegisterInfo>();


	/**
	 * 转发服务，将数据转发给809
	 */
	@Autowired
	private ITransferGpsService transferGpsService;

	@Value("#{config.checkRegister}")  
	private boolean checkRegister;


	private boolean continueAck = true;

	@Value("#{config.transferTo809Enabled}")  
	private boolean transferTo809Enabled;

	private List<AckQueue> queueList = new ArrayList();

	public AckService() {
		for (int m = 0; m < 20; m++) {
			final int sn = m;
			Thread processRealDataThread = new Thread(new Runnable() {
				public void run() {
					ProcessRealDataThreadFunc(sn);
				}
			});

			AckQueue aq = new AckQueue(processRealDataThread, 150);
			queueList.add(aq);
		}
	}

	public void stop() {
		continueAck = false;
		for (AckQueue q : queueList) {
			q.stop();
		}
	}

	public void beginAck(T808Message tm) {
		int msgType = tm.getMessageType();
		String simNo = tm.getHeader().getSimId();
		int size = this.queueList.size();
		for (int m = 0; m < size; m++) {
			AckQueue queue = queueList.get(m);
			if (queue.contains(simNo) || queue.isFull() == false
					|| (m == size - 1)) {
				queue.enQueue(tm);
				break;
			}
		}

	}

	private void ProcessRealDataThreadFunc(int m) {

		AckQueue aq = (AckQueue) queueList.get(m);
		ConcurrentLinkedQueue<T808Message> dataQueue = aq.getDataQueue();
		int times = 0;
		while (continueAck) {
			try {
				if (times > 0 && times % 10 == 0 && m == 0) {
					times = 0;
					int qs= dataQueue.size();
					if (qs > 20)
						logger.error("队列" + m + "排队等待应答数量:" + qs);
				}

				T808Message tm = dataQueue.poll();
				int k = 0;
				while (tm != null) {
					SendGeneralAck(tm);
					if (k++ > 50)
						break;
					tm = dataQueue.poll();
				}

			} catch (Exception ex) {
				logger.error(ex.getMessage(), ex);
			}

			times++;
			try {
				Thread.sleep(50L);
			} catch (InterruptedException e1) {
			}
		}
	}

	/**
	 * 根据收到的808消息，进行应答
	 * 
	 * @param msgFromTerminal
	 */
	private void SendGeneralAck(T808Message msgFromTerminal) {
		int msgType = msgFromTerminal.getMessageType();
		if (msgType == 0)
			return;

		String simNo = msgFromTerminal.getSimNo();

		//根据不同消息类型进行应答
		if (msgType == 0x0100) {
			// 注册请求
			JT_0100 registerData = (JT_0100) msgFromTerminal
					.getMessageContents();
			if (registerData == null) {
				return;
			}
			msgFromTerminal.setPlateNo(registerData.getPlateNo());
			int result = 0;// 默认注册成功

			VehicleData rd = realDataService.getVehicleData(simNo);
			if (rd == null) {
				logger.error("注册车辆不存在, simNo:" + simNo);
				result = 2;
			}
			transferRegiser(simNo, registerData);
			if (checkRegister) {
				// 根据sim卡号获取车辆信息，判断是否是系统内录入的车辆
				VehicleData vd = this.realDataService
						.getVehicleByPlateNo(msgFromTerminal.getPlateNo());

				if (vd != null
						&& vd.getPlateColor() == registerData.getPlateColor()) {
					if (vehicleRegisterMap.containsKey(vd.getPlateNo())) {
						result = 1;// 该车辆已经注册
					}

					if (result == 0) {
						Terminal term = realDataService
								.getTerminalByTermNo(registerData
										.getTerminalId());
						if (term == null) {
							result = 4;// 终端不存在
						} else {
							if (terminalRegisterMap.containsKey(term
									.getTermNo())) {
								result = 3;// 该终端已经注册
							}
						}
					}

				} else
					result = 2;// 车辆不存在
				if (result == 0) {
					terminalRegisterMap
							.put(registerData.getTerminalId(), simNo);
					vehicleRegisterMap.put(vd.getPlateNo(), simNo);
					registerMap.put(simNo, registerData.getPlateNo() + ","
							+ registerData.getTerminalId());
				}
			}

			JT_8100 echoData = new JT_8100();
			echoData.setRegisterResponseMessageSerialNo(msgFromTerminal
					.getHeader().getMessageSerialNo());
			echoData.setRegisterResponseResult((byte) result);
			echoData.setRegisterNo(authencateNo);

			T808Message ts = new T808Message();
			ts.setMessageContents(echoData);
			ts.setHeader(new T808MessageHeader());
			ts.getHeader().setMessageType(0x8100);
			ts.getHeader().setSimId(simNo);
			// ts.Header.MessageSize = echoData.WriteToBytes().Length;
			ts.getHeader().setIsPackage(false);

			getMessageSender().Send808Message(ts);

		} else if (msgType == 0x0001) {
			// 收到终端的通用应答，根据应答，更新命令的执行状态
			JT_0001 answerData = (JT_0001) msgFromTerminal.getMessageContents();
			short platformSn = answerData.getResponseMessageSerialNo();
			String cmdStatus = answerData.getResponseResult() == 0 ? TerminalCommand.STATUS_SUCCESS
					: TerminalCommand.STATUS_FAILED;
			if (answerData.getResponseResult() >= 2) {
				cmdStatus = TerminalCommand.STATUS_NOT_SUPPORT;
			}

			String ackSimNo = msgFromTerminal.getHeader().getSimId();
			TerminalCommand tc = null;
			int tryTimes = 0;
			while (tc == null && tryTimes++ < 3) {
				tc = this.commandParseService.UpdateStatus(simNo, platformSn, cmdStatus);
				if(tc != null)
					break;
				try {
					Thread.sleep(5);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			if (tc == null || tryTimes > 1) {
				// String strMsgType = "0x"
				// + Tools.ToHexString((int)answerData.getResponseMessageId(),
				// 2);
				// String msgDescr = "[" + strMsgType + "]"
				// + JT808Constants.GetDescr(strMsgType);
				logger.error("无法找到下发的命令:"+simNo);
			}
			if (tc != null && TerminalCommand.FROM_GOV.equals(tc.getOwner())) {
				VehicleData vd = this.realDataService.getVehicleData(tc
						.getSimNo());
				// 如果是809下发的命令，则需要将终端的应答转发给809上级平台
				int result = answerData.getResponseResult() == 0 ? 0 : 1;
				if (tc.getCmdType() == JT808Constants.CMD_DIAL_BACK) {
					// 监听命令应答
					this.transferGpsService.transferListenTerminalAck(
							vd.getPlateNo(), vd.getPlateColor(), (byte) result);
				} else if (tc.getCmdType() == JT808Constants.CMD_CONTROL_TERMINAL) {
					// 紧急接入命令应答
					this.transferGpsService.transferEmergencyAccessAck(
							vd.getPlateNo(), vd.getPlateColor(), (byte) result);
				} else if (tc.getCmdType() == JT808Constants.CMD_SEND_TEXT) {
					int msgId = Integer.parseInt(tc.getCmd());
					// 文本信息下发应答
					this.transferGpsService.transferTextInfoAck(
							vd.getPlateNo(), vd.getPlateColor(), msgId,
							(byte) result);
				}
			}

		} else if (msgType == 0x0500) {
			// 车辆控制应答
			JT_0500 answerData = (JT_0500) msgFromTerminal.getMessageContents();
			short platformSn = answerData.getResponseMessageSerialNo();
			String cmdStatus = TerminalCommand.STATUS_SUCCESS;
			//更新车辆控制指令的应答状态
			commandParseService.UpdateStatus(msgFromTerminal.getHeader().getSimId(),
					platformSn, cmdStatus);
		} else if (msgType == 0x0104) {
			// 查询终端参数结果的应答是平台通用应答
			JT_8001 echoData = new JT_8001();
			echoData.setResponseMessageSerialNo(msgFromTerminal.getHeader()
					.getMessageSerialNo());
			echoData.setResponseMessageId((short) msgFromTerminal.getHeader()
					.getMessageType());
			echoData.setResponseResult((byte) 0);

			T808Message ts = new T808Message();
			ts.setMessageContents(echoData);
			ts.setHeader(new T808MessageHeader());
			ts.getHeader().setMessageType(0x8001);
			ts.getHeader().setSimId(msgFromTerminal.getHeader().getSimId());
			// ts.Header.MessageSize = echoData.WriteToBytes().Length;
			ts.getHeader().setIsPackage(false);
			getMessageSender().Send808Message(ts);

		}
		else {
			int ackResult = 0;// 应答结果־
			if (msgType == 0x0201) {
				// 位置信息查询
				JT_0201 answerData = (JT_0201) msgFromTerminal
						.getMessageContents();
				short platformSn = answerData.getResponseMessageSerialNo();
				String cmdStatus = TerminalCommand.STATUS_SUCCESS;
				commandParseService.UpdateStatus(msgFromTerminal.getHeader()
						.getSimId(), platformSn, cmdStatus);
			}
			//终端注销
			else if (msgType == 0x0003) {
				if (registerMap.containsKey(simNo)) {
					String registerData = "" + registerMap.get(simNo);
					if (registerData != null) {
						String[] temp = registerData.split(",");
						String plateNo = temp[0];
						String terminalId = temp[1];

						vehicleRegisterMap.remove(plateNo);
						terminalRegisterMap.remove(terminalId);
						registerMap.remove(simNo);
					}
				}
				// return;
			} else if (msgType == 0x0102) {
				//终端鉴权
				JT_0102 cmdData = (JT_0102) msgFromTerminal
						.getMessageContents();
				//转发注册
				transferRegister(simNo);
				if(checkRegister)
				{
					ackResult = 1;
					if (cmdData != null ) {
						ackResult = this.authencateNo.equals(cmdData
								.getRegisterNo()) ? 0 : 1;
					}
				}
			} else if (msgType == 0x0801){
				if(msgFromTerminal.getHeader().getMessagePacketNo() == msgFromTerminal.getHeader().getMessageTotalPacketsCount())
				{
					return;
				}
			}
			// 平台通用应答
			JT_8001 echoData = new JT_8001();
			echoData.setResponseMessageSerialNo(msgFromTerminal.getHeader()
					.getMessageSerialNo());
			echoData.setResponseMessageId((short) msgType);
			echoData.setResponseResult((byte) ackResult); 

			T808Message ts = new T808Message();
			ts.setMessageContents(echoData);
			ts.setHeader(new T808MessageHeader());
			ts.getHeader().setMessageType(0x8001);
			ts.getHeader().setSimId(simNo);
			ts.getHeader().setIsPackage(false);
			getMessageSender().Send808Message(ts);
		}

	}

	/**
	 * 转发注册信息给809
	 * @param simNo
	 * @param registerData
	 */
	private void transferRegiser(String simNo, JT_0100 registerData) {
		try {
			if (transferTo809Enabled == false)
				return;
			VehicleRegisterInfo vi = this.getVehicleRegisterInfo(simNo);
			vi.setTerminalId(registerData.getTerminalId());
			vi.setTerminalModel(registerData.getTerminalModelNo());
			vi.setTerminalVendorId(registerData.getManufactureId());
			vi.setPlateColor(registerData.getPlateColor());
			vi.setPlateNo(registerData.getPlateNo());
			/**
			VehicleData vd = this.realDataService.getVehicleData(simNo);
			if (vd != null) {
				vi.setDepId(vd.getDepId());
				vi.setPlateNo(vd.getPlateNo());
			} else {
				vi.setPlateNo(registerData.getPlateNo());
			}
			if (StringUtil.isNullOrEmpty(vi.getPlateNo()) == false) {
				//vi.setUpdateDate(new Date());
				BaseDao.saveOrUpdate(vi);
			}
			*/

			this.transferGpsService.transferRegisterInfo(vi); //调用转发服务转发给809
		} catch (Exception ex) {
			logger.error(ex.getMessage(),ex);
		}
	}

	/**
	 * 将终端注册信息，转换成809转发给809上级平台
	 * @param simNo
	 */
	private void transferRegister(String simNo) {
		try {

			if (transferTo809Enabled == false)
				return;
			
			VehicleRegisterInfo vi = this.getVehicleRegisterInfo(simNo);
			if (vi.getPlateNo() == null) {
				VehicleData vd = this.realDataService.getVehicleData(simNo);
				if (vd != null && vd.getTermId() > 0) {
					Terminal terminal = terminalService.load(vd
							.getTermId());

					if (terminal != null) {
						vi.setPlateNo(vd.getPlateNo());
						vi.setPlateColor(vd.getPlateColor());
						vi.setTerminalId(terminal.getTermNo()); 
						vi.setTerminalModel(terminal.getTermType());
						vi.setTerminalVendorId(terminal.getMakeNo());
						vi.setDepId(vd.getDepId());
						vi.setSimNo(vd.getSimNo());

					}
				}
			}
			if (vi.getPlateNo() != null) {
				//vi.setUpdateDate(new Date());
				//BaseDao.saveOrUpdate(vi);
			}

			if (transferTo809Enabled == false)
				return;
			this.transferGpsService.transferRegisterInfo(vi);
		} catch (Exception ex) {
			logger.error(ex.getMessage(),ex);
		}

	}

	private VehicleRegisterInfo getVehicleRegisterInfo(String simNo) {
		VehicleRegisterInfo vi = null;
		if (vehicleRegisterInfoMap.containsKey(simNo))
			vi = (VehicleRegisterInfo) vehicleRegisterInfoMap.get(simNo);
		else {
			vi = new VehicleRegisterInfo();
			vi.setSimNo(simNo);
			vehicleRegisterInfoMap.put(simNo, vi);
		}
		/**
		 * String hql = "from VehicleRegisterInfo where simNo = ?";
		 * 
		 * VehicleRegisterInfo vi = (VehicleRegisterInfo) this.BaseDao.find(hql,
		 * simNo); if (vi == null) { vi = new VehicleRegisterInfo();
		 * vi.setSimNo(simNo); }
		 */
		return vi;
	}

	public void setMessageSender(IMessageSender messageSender) {
		this.messageSender = messageSender;
	}

	public IMessageSender getMessageSender() {
		return messageSender;
	}



}
